// CVV.cpp : Defines the entry point for the console application.
//

#include "DigitMLP.h"

using namespace std;



class ValueAnalyzer {
private:
	IplImage* gray, *gray_cut, *gray_rot, *gray_series;
	IplImage* binarized, *bin_series;
	vector<IplImage*> symbols;
	vector<int> xbegins, xends;
	IplImage* display;
	double rectarea, circlearea, circleratio, rectratio;
	vector<CBlob*> rects, circles, distfiltered, centerfiltered;
	bool left;
	int cost;
	int min_dist;
	string series;
	
	

public:
	string path;
	ValueAnalyzer(char* filename) {
		path = string(filename);
		IplImage* img=cvLoadImage( filename );
		if(!img) throw MyEx("There's no such file.");
		gray = cvCreateImage( cvSize(img->width, img->height), IPL_DEPTH_8U, 1 );
		cvCvtColor( img, gray, CV_RGB2GRAY );
		cvReleaseImage( &img );
		IplConvKernel* element = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_RECT,NULL);
		cvNormalize(gray, gray, 0, 255, CV_MINMAX);
		rectarea = 120;
		circlearea = 53;
		circleratio = 1.75;
		rectratio = 2;
		cost = -1;
		left = true;
		binarized = 0;
		gray_cut = 0;
		gray_rot = 0;
		gray_series = 0;
		bin_series = 0;
		display = 0;
		series = "";
		min_dist = 5000;
	}

	~ValueAnalyzer() {
		cvReleaseImage(&gray);
		cvReleaseImage(&gray_cut);
		cvReleaseImage(&gray_rot);
		cvReleaseImage(&binarized);
		cvReleaseImage(&display);
		cvReleaseImage(&gray_series);
		cvReleaseImage(&bin_series);
		cvDestroyWindow("Marked image");
	}

	void RotateToHorizontal() {
		IplImage *tmp = cvCreateImage( cvSize(gray->width, gray->height), gray->depth, gray->nChannels);
        cvThreshold(gray, tmp, 50, 255, CV_THRESH_OTSU);
		IplConvKernel* element = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_RECT,NULL);
		cvMorphologyEx(tmp,tmp,NULL,element,CV_MOP_OPEN,1);
		cvMorphologyEx(tmp,tmp,NULL,element,CV_MOP_CLOSE,3);
		cvReleaseStructuringElement(  &element );
		CBlobResult blobs;
	    blobs = CBlobResult( tmp, NULL, 0 );
		blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_LESS, 500 );
		CBlob paper;
		blobs.GetNthBlob( CBlobGetArea(), 0, paper);
		CBlobContour* c = paper.GetExternalContour();
		CvMoments ms;
		cvMoments( paper.GetExternalContour()->GetContourPoints(), &ms, 1);
		double m11 = cvGetCentralMoment(&ms, 1, 1);
		double m20 = cvGetCentralMoment(&ms, 2, 0);
		double m02 = cvGetCentralMoment(&ms, 0, 2);
		double angle = 180 * 0.5 * atan( 2*m11 / (m20 - m02) ) / CV_PI;
		CBlobGetMinXatMinY cb1;
		CBlobGetMaxXatMaxY cb2;
		if ( paper.GetBoundingBox().height > paper.GetBoundingBox().width ) angle = 90 + angle;
		gray_rot = rotateImage(gray, angle);
		cvReleaseImage(&tmp);
	}

	void ResizeToRawPaper() {
		IplImage *tmp = cvCreateImage( cvSize(gray_rot->width, gray_rot->height), gray_rot->depth, gray_rot->nChannels);
		cvThreshold(gray_rot, tmp, 50, 255, CV_THRESH_OTSU);
		IplConvKernel* element = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_RECT,NULL);
		cvMorphologyEx(tmp,tmp,NULL,element,CV_MOP_OPEN,1);
		cvMorphologyEx(tmp,tmp,NULL,element,CV_MOP_CLOSE,3);
		cvReleaseStructuringElement(  &element );
		CBlobResult blobs;
	    blobs = CBlobResult( tmp, NULL, 0 );
		blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_LESS, 500 );
		CBlob paper;
		blobs.GetNthBlob( CBlobGetArea(), 0, paper);
		int maxx = (int)paper.MaxX(), minx = (int)paper.MinX(), maxy = (int)paper.MaxY(), miny = (int)paper.MinY();
		int width = maxx-minx, height = maxy-miny;
		int max = (width >= height) ? width : height;
		cvSetImageROI(gray_rot, cvRect(minx, miny, maxx-minx, maxy-miny));
		gray_cut = cvCreateImage( cvSize(750, (int)750*height/width), IPL_DEPTH_8U, 1);
		cvResize(gray_rot,gray_cut,CV_INTER_LANCZOS4);
		cvReleaseImage(&tmp);
	}

	void Binarize(double divider) {
		if(binarized) cvReleaseImage(&binarized);
		binarized = bernsen(gray_cut, 21, true, divider);
		cvDrawRect(binarized, cvPoint(0, 0), cvPoint(90, binarized->height), cvScalar(0, 0, 0), -1);
		cvDrawRect(binarized, cvPoint(binarized->width-90, 0), cvPoint(binarized->width, binarized->height), cvScalar(0, 0, 0), -1);
		cvDrawRect(binarized, cvPoint(binarized->width/2-205, 0), cvPoint(binarized->width/2+205, binarized->height), cvScalar(0, 0, 0), -1);
		cvDrawRect(binarized, cvPoint(0, 0), cvPoint(500, binarized->height/1.75), cvScalar(0, 0, 0), -1);
		cvDrawRect(binarized, cvPoint(binarized->width - 500, binarized->height*0.4), cvPoint(binarized->width, binarized->height), cvScalar(0, 0, 0), -1);
		cvDrawRect(binarized, cvPoint(0, 0), cvPoint(binarized->width, 10), cvScalar(0, 0, 0), -1);
		cvDrawRect(binarized, cvPoint(0, binarized->height-10), cvPoint(binarized->width, binarized->height), cvScalar(0, 0, 0), -1);
		cvDrawRect(binarized, cvPoint(0, binarized->height/2-75), cvPoint(binarized->width, binarized->height/2+75), cvScalar(0, 0, 0), -1);
		IplConvKernel* element = cvCreateStructuringElementEx(3,3,1,1,CV_SHAPE_RECT,NULL);
		cvMorphologyEx(binarized,binarized,NULL,element,CV_MOP_CLOSE,1);
		cvReleaseStructuringElement(  &element );
	}

	void DoMarkUp() {
		if(display) cvReleaseImage(&display);
		rects.clear();
		circles.clear();
		distfiltered.clear();
		centerfiltered.clear();
		left = true;
		CBlobResult blobs;
		CBlob *currentBlob;
		vector<CBlob*> c;
		display = cvCreateImage(cvGetSize(binarized), IPL_DEPTH_8U,3);
		cvMerge( gray_cut, gray_cut, gray_cut, NULL, display);
		//cvMerge( binarized, binarized, binarized, NULL, display);
		blobs = CBlobResult( binarized, NULL, 0 );
		blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_LESS, 0.4 * circlearea );
		blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_GREATER, 1.55 * rectarea );
		blobs.Filter( blobs, B_EXCLUDE, CBlobGetBreadth(), B_LESS, 2 );
		blobs.Filter( blobs, B_EXCLUDE, CBlobGetHullArea(), B_GREATER, 1.55 * rectarea );
		blobs.Filter( blobs, B_EXCLUDE, CBlobGetRoughness(), B_GREATER, 1.3 );
		for (int i = 0; i < blobs.GetNumBlobs(); i++ )
		{
			CBlobGetElongation ge;
			currentBlob = blobs.GetBlob(i);
			double ratio = currentBlob->Area() / currentBlob->Perimeter();
			double area = currentBlob->Area();
			double longevity = (currentBlob->MaxX() - currentBlob->MinX()) / (currentBlob->MaxY() - currentBlob->MinY());
			if (ratio > circleratio * 0.65 && ratio < circleratio * 1.35 && area < 1.6 * circlearea && ge(*currentBlob) < 2.5 && ge(*currentBlob) > 0.8) {
				circles.push_back(currentBlob);
			}
			else if (ratio > rectratio*0.7 && ratio < rectratio * 1.4 && area < 1.4*rectarea && area > 0.5*rectarea && longevity < 5) {
				rects.push_back(currentBlob);
			}
			else currentBlob->FillBlob( display, CV_RGB(255,0,0));
		}
		for (vector<CBlob*>::iterator it=rects.begin(); it != rects.end(); it++) {
			CBlobGetLength cbgl;
			CBlobGetBreadth cbgb;
			double ratio = cbgl(**it)/cbgb(**it);
			if(ratio < 2) c.push_back(*it);
		}
		for(unsigned int i = 0; i<c.size(); i++) rects.erase(remove(rects.begin(), rects.end(), c[i]),rects.end());
		c.clear();

		for (vector<CBlob*>::iterator it=rects.begin(); it != rects.end(); it++) {
			CBlobGetDistanceFromPoint cbgdfp(binarized->width/2, binarized->height/2);
			if(cbgdfp(**it) < 230)  {
				centerfiltered.push_back(*it);
				c.push_back(*it);
			}
		}
		for(unsigned int i = 0; i<c.size(); i++) rects.erase(remove(rects.begin(), rects.end(), c[i]),rects.end());
		c.clear();

		for (vector<CBlob*>::iterator it=rects.begin(); it != rects.end(); it++) {
			double min = 5000;
			int minpos = 0, pos = 0;
			for (vector<CBlob*>::iterator it2=circles.begin(); it2 != circles.end(); it2++) {
				if (metric(*it, *it2) < min) {
					minpos = pos;
					min = metric(*it, *it2);
				}
				pos++;
			}
			int xpos1 = ((*it)->MaxX() + (*it)->MinX() )/2;
			int xpos2 = (circles.size()) ? ((circles[minpos]->MaxX() + circles[minpos]->MinX() )/2) : 0;
			if(min > 70 || abs(xpos1-xpos2) > 8) {
				distfiltered.push_back(*it);
				c.push_back(*it);
			}
		}
		for(unsigned int i = 0; i<c.size(); i++) rects.erase(remove(rects.begin(), rects.end(), c[i]),rects.end());
		c.clear();
		
		for (vector<CBlob*>::iterator it=circles.begin(); it != circles.end(); it++) {
			double min = 5000;
			int minpos = 0, pos = 0;
			for (vector<CBlob*>::iterator it2=rects.begin(); it2 != rects.end(); it2++) {
				if (metric(*it, *it2) < min) {
					min = metric(*it, *it2);
					minpos = pos;
				}
				pos++;
			}
			int xpos1 = ((*it)->MaxX() + (*it)->MinX() )/2;
			int xpos2 = (rects.size()) ? ((rects[minpos]->MaxX() + rects[minpos]->MinX() )/2) : 0;
			if(min > 70 || abs(xpos1-xpos2) > 8) {
				distfiltered.push_back(*it);
				c.push_back(*it);
			}
		}
		for(unsigned int i = 0; i<c.size(); i++) circles.erase(remove(circles.begin(), circles.end(), c[i]),circles.end()); 

		int lefts=0, rights = 0;
		for (vector<CBlob*>::iterator it=rects.begin(); it != rects.end(); it++) {
			if( (*it)->MaxX() > binarized->width/2 ) rights++;
			else lefts++;
			(*it)->FillBlob( display, CV_RGB(0,255,0));
		}
		for (vector<CBlob*>::iterator it=circles.begin(); it != circles.end(); it++) (*it)->FillBlob( display, CV_RGB(255,200,0));
		for (vector<CBlob*>::iterator it=centerfiltered.begin(); it != centerfiltered.end(); it++) (*it)->FillBlob( display, CV_RGB(0,0,255));
		for (vector<CBlob*>::iterator it=distfiltered.begin(); it != distfiltered.end(); it++) (*it)->FillBlob( display, CV_RGB(255,0,255));
		cost = GetValue();
		left = lefts>=rights;
		if(!left) {
			gray_cut = rotateImage(gray_cut, 180);
			display = rotateImage(display, 180);
		}

		double lowercircle = 0, upperrect = 5000;
		for (int i = 0; i < circles.size(); i++) {
			int ypos = (circles[i]->MaxY() + circles[i]->MinY() )/2;
			if(ypos > lowercircle) lowercircle = ypos;
		}
		for (int i = 0; i < rects.size(); i++) {
			int ypos = (rects[i]->MaxY() + rects[i]->MinY() )/2;
			if(ypos < upperrect) upperrect = ypos;
		}
		min_dist = upperrect - lowercircle;

		cvNamedWindow( "Marked image", CV_WINDOW_AUTOSIZE);
		cvShowImage( "Marked image", display );
	}

	void GetSeries() {
		int xpos, ypos, width = 155, height = 35; 
		xpos = 585;
		ypos = 40;
		while(ypos < gray_cut->height - height*3) {
			cvResetImageROI(gray_cut);
			cvSetImageROI(gray_cut, cvRect(xpos, ypos, width, height));
			IplImage* tmp = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1);
			cvResize(gray_cut, tmp, CV_INTER_LINEAR); 
			cvResetImageROI(gray_cut);
			cvSetImageROI(gray_cut, cvRect(xpos, ypos+3, width, height));
			IplImage* tmp2 = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1);
			cvResize(gray_cut, tmp2, CV_INTER_LINEAR); 
			IplImage* tmpbin = cvCreateImage( cvSize(tmp->width, tmp->height), tmp->depth, tmp->nChannels);
			cvAdaptiveThreshold(tmp, tmpbin, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 15, 30);
			IplImage* tmpbin2 = cvCreateImage( cvSize(tmp->width, tmp->height), tmp->depth, tmp->nChannels);
			cvAdaptiveThreshold(tmp2, tmpbin2, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 15, 30);
			if (HasClearTop(tmpbin, 8) == true && HasClearTop(tmpbin2, 8) == false) break;
			ypos++;
			cvReleaseImage(&tmp);
			cvReleaseImage(&tmpbin);
		}
		if(ypos > gray_cut->height*0.4) {
			ypos = 45;
			while(ypos < gray_cut->height - height*3) {
				cvResetImageROI(gray_cut);
				cvSetImageROI(gray_cut, cvRect(xpos, ypos, width, height));
				IplImage* tmp = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1);
				cvResize(gray_cut, tmp, CV_INTER_LINEAR); 
				cvResetImageROI(gray_cut);
				cvSetImageROI(gray_cut, cvRect(xpos, ypos+3, width, height));
				IplImage* tmp2 = cvCreateImage( cvSize(width, height), IPL_DEPTH_8U, 1);
				cvResize(gray_cut, tmp2, CV_INTER_LINEAR); 
				IplImage* tmpbin = cvCreateImage( cvSize(tmp->width, tmp->height), tmp->depth, tmp->nChannels);
				cvAdaptiveThreshold(tmp, tmpbin, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 15, 30);
				IplImage* tmpbin2 = cvCreateImage( cvSize(tmp->width, tmp->height), tmp->depth, tmp->nChannels);
				cvAdaptiveThreshold(tmp2, tmpbin2, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 15, 30);
				if (HasClearTop(tmpbin, 25) == true && HasClearTop(tmpbin2, 25) == false) break;
				ypos++;
				cvReleaseImage(&tmp);
				cvReleaseImage(&tmpbin);
			}
		}
        //ypos += 2;
		{
			cvResetImageROI(gray_cut);
			cvSetImageROI(gray_cut, cvRect(gray_cut->width - width*1.25, ypos, width*1.25, height));
			IplImage* tmp = cvCreateImage( cvSize(width*1.25, height), IPL_DEPTH_8U, 1);
			cvResize(gray_cut, tmp, CV_INTER_LINEAR); 
			IplImage* tmpbin = cvCreateImage( cvSize(tmp->width, tmp->height), tmp->depth, tmp->nChannels);
			cvAdaptiveThreshold(tmp, tmpbin, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 15, 30);
			IplConvKernel* element2 = cvCreateStructuringElementEx(2,2,1,1,CV_SHAPE_RECT,NULL);
			cvMorphologyEx(tmpbin,tmpbin,NULL,element2,CV_MOP_OPEN,15);
			cvReleaseStructuringElement(  &element2 );
			cvNot(tmpbin, tmpbin);
			CBlobResult blobs = CBlobResult( tmpbin, NULL, 0 );
			CBlob *currentBlob;
			blobs.Filter( blobs, B_EXCLUDE, CBlobGetArea(), B_LESS, 30 );
			for (int i = 0; i < blobs.GetNumBlobs(); i++ )
			{
				currentBlob = blobs.GetBlob(i);
				double width = currentBlob->MaxX() - currentBlob->MinX();
				double height = currentBlob->MaxY() - currentBlob->MinY();
				if( (width/height > 1.25) && (currentBlob->MaxX() > tmp->width/2)  ) {
					xpos = gray_cut->width - tmpbin->width + currentBlob->MaxX() - 165;
					if(cost == 1000) xpos += 25;
					break;
				}
			}
			cvReleaseImage(&tmp);
			cvReleaseImage(&tmpbin);
		}

		cvResetImageROI(gray_cut);
		int cutwidth = (width+xpos < gray_cut->width)? width - 1 : gray_cut->width - xpos - 1;
		cvSetImageROI(gray_cut, cvRect(xpos, ypos, cutwidth, height));
		gray_series = cvCreateImage( cvSize(cutwidth*3, height*3), IPL_DEPTH_8U, 1);
		cvResize(gray_cut, gray_series, CV_INTER_LANCZOS4); 
		cvNormalize(gray_series, gray_series, 0, 255, CV_MINMAX);
		bin_series = cvCreateImage( cvSize(gray_series->width, gray_series->height), gray_series->depth, gray_series->nChannels);
		cvAdaptiveThreshold(gray_series, bin_series,255,CV_ADAPTIVE_THRESH_MEAN_C,CV_THRESH_BINARY,145, 30);
		IplConvKernel* element = cvCreateStructuringElementEx(2,2,1,1,CV_SHAPE_RECT,NULL);
		//cvMorphologyEx(bin_series,bin_series,NULL,element,CV_MOP_OPEN,1);
		//cvErode(bin_series, bin_series, element,1);
		cvReleaseStructuringElement(  &element );
		if(VerticalLine(bin_series, 0) > 18) {
			int n = 0;
			while (VerticalLine(bin_series, n) > 18) {FlushVerticalLine(bin_series, n); n++; }
		}
		IplImage *temp = cvCreateImage( cvGetSize(bin_series), IPL_DEPTH_8U, 1);
		cvNot(bin_series, temp);
		CBlobResult blobs = CBlobResult( temp, NULL, 0 );
		CBlob *currentBlob;
		for (int i = 0; i < blobs.GetNumBlobs(); i++ )
		{
			currentBlob = blobs.GetBlob(i);
			double width = currentBlob->MaxX() - currentBlob->MinX();
			double height = currentBlob->MaxY() - currentBlob->MinY();
			if (currentBlob->Area() < 128 || width/height > 1.25 || (currentBlob->Area() < 225 && currentBlob->MinY() < 5 ) )
				currentBlob->FillBlob(bin_series, cvScalar(255));
		}
		cvReleaseImage(&temp);
		cvDrawRect(display, cvPoint(xpos, ypos), cvPoint(xpos+width, ypos+height), CV_RGB(255, 170, 0), 2);
		cvNamedWindow( "Series", CV_WINDOW_AUTOSIZE);
		cvShowImage( "Series", bin_series );
		cvShowImage( "Marked image", display );
	}

	

	void CalculateNominal() {
		RotateToHorizontal();
		ResizeToRawPaper();
		Binarize(1.7);
		DoMarkUp();
		int value = GetValue();
		if(value == -1 || min_dist > 15) {
			Binarize(2.1);
			DoMarkUp();
			value = GetValue();
		}
		else return;
		if(value == -1 || min_dist > 15) {
			Binarize(2.4);
			DoMarkUp();
			value = GetValue();
		}
		else return;
		if(value == -1 || min_dist > 15) {
			Binarize(1.5);
			DoMarkUp();
			value = GetValue();
		}
		else return;
	}


	void CutSymbols() {
		int ybegin = 0, yend = bin_series->height - 1;
		int xbegin[9];
		int xend[9];
		int ybeg[9];
		int yending[9];
		for (int y = 0; y < bin_series->height; y++) {
			int sum = 0;
			for (int x = 0; x < bin_series->width; x++) {
				if (bin_series->imageData[bin_series->widthStep*y + x] == 0) sum++;
			}
			if(sum>8) {
				ybegin = y;
				break;
			}
		}
		for (int y = bin_series->height - 1; y > 0; y--) {
			int sum = 0;
			for (int x = 0; x < bin_series->width; x++) {
				if (bin_series->imageData[bin_series->widthStep*y + x] == 0) sum++;
			}
			if(sum>8) {
				yend = y;
				break;
			}
		}
		if (ybegin > 1) ybegin-= 2;
		if (yend < bin_series->height - 3) yend +=2;

		IplImage* d = cvCreateImage(cvGetSize(bin_series), IPL_DEPTH_8U,3);
		cvMerge( bin_series, bin_series, bin_series, NULL, d);
		for(int i = 0; i < 9; i++) {
			xbegin[i] = FindSymbolLine(bin_series, (i==0)?0:xend[i-1]  );
			xend[i] = FindClearLine(bin_series, xbegin[i], xbegin[i]);
			xbegin[i]-=3;
			xend[i]++;
		}
		for(int i = 0; i < 9; i++) {
			ybeg[i] = ybegin;
			yending[i] = yend;
			if((xend[i] - xbegin[i]) > 15) {
				while(ClearHorizontalRange(bin_series, ybeg[i], xbegin[i], xend[i])) ybeg[i]++;
				while(ClearHorizontalRange(bin_series, yending[i], xbegin[i], xend[i])) yending[i]--;
				while(ClearVerticalRange(bin_series, xbegin[i], ybeg[i], yending[i])) xbegin[i]++;
				while(ClearVerticalRange(bin_series, xend[i], ybeg[i], yending[i])) xend[i]--;
				cvDrawLine(d, cvPoint(xbegin[i],ybeg[i]), cvPoint(xbegin[i], yending[i]), CV_RGB(255, 0, 0) );
				cvDrawLine(d, cvPoint(xend[i],ybeg[i]), cvPoint(xend[i], yending[i]), CV_RGB(255, 0, 0) );
				cvDrawLine(d, cvPoint(xbegin[i],ybeg[i]), cvPoint(xend[i], ybeg[i]), CV_RGB(255, 0, 0) );
				cvDrawLine(d, cvPoint(xbegin[i],yending[i]), cvPoint(xend[i], yending[i]), CV_RGB(255, 0, 0) );
				cvResetImageROI(bin_series);
				cvSetImageROI(bin_series, cvRect(xbegin[i], ybeg[i], xend[i]-xbegin[i], yending[i]-ybeg[i]));
				IplImage* img = cvCreateImage(cvSize(35,60), IPL_DEPTH_8U,1);
				cvResize(bin_series, img, CV_INTER_LINEAR); 
				symbols.push_back(img);
				xbegins.push_back(xbegin[i]);
				xends.push_back(xend[i]);
			}
		}
		cvShowImage( "Series", d);
	}

	void RecognizeDigits() {
		char buf[10];
		DigitMLP d("MLP_digits.dat");
		for(int i = 0; i < symbols.size(); i++) {
				for(int j = 0; j < 10; j++) buf[j] = '?';
				int digit = d.predict(symbols[i]);
				itoa(digit, buf, 10);
				series += buf[0];
		}
		string temp(series);
		series = "";
		for(int i = temp.size()-7; i < temp.size(); i++) {
			series+=temp[i];
			if(i != temp.size()-1 ) series+=" ";
		}
	}

	int GetValue() {
		int r = rects.size(), c = circles.size();
		switch(r) {
			case 1: 
			{
				switch(c) {
					case 1:  return 10; break;
					case 2:  return 50; break;
					default: return -1; break;
				}
				break;
			}
			case 2: 
			{
				if (c==1)  return 100;
				else if (c==2)  return 500;
				else return -1;
				break;
			}
			case 3:
			{
				switch(c) {
					case 1:  return 1000; break;
					case 2:  return 5000; break;
					default: return -1; break;
				}
				break;
			}
			default: return -1; break;
		}
	}

	string GetSeriesString() {
		return series;
	}
};

int main(int argc, char* argv[])
{
	try {
		srand ( time(NULL) );
		ValueAnalyzer va(argv[1] ? argv[1] : "DSC01310.jpg");
		va.CalculateNominal();
		cout<<"Value: "<<va.GetValue()<<endl;
		if(va.GetValue() != -1) {
			va.GetSeries();
			va.CutSymbols();
			va.RecognizeDigits();
			cout<<"Series: "<<va.GetSeriesString()<<endl;
		}
		string s = va.path+".txt";
		ofstream f(s.c_str());
		f<<va.GetValue()<<endl;
		f<<va.GetSeriesString()<<endl;
		//cvWaitKey(0);
	}
	catch (MyEx& e) {
		cout<<endl<<"Error: "<<e.what<<endl<<endl;
	}
	catch (exception& e) {
		cout<<endl<<"OLOLO: "<<e.what()<<endl<<endl;
	}
	return 0;
}
